/*
 * graph2D
 * Copyright (c) 2009 Shun Moriya <shun@mnu.sakura.ne.jp>
 *
 * The MIT License
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "audioPlayer.h"
#include "data.h"

#if defined(TARGET_IPHONE)
#include "platform/iOS/audioPlayer_impl.h"
#elif defined(TARGET_WINDOWS)
#include "platform/windows/audioPlayer_impl.h"
#endif

#define ENABLE_VOLUME_EVENT_PAUSE	(0x01)
#define ENABLE_VOLUME_EVENT_STOP	(0x02)
#define ENABLE_VOLUME_EVENT_MASK	(ENABLE_VOLUME_EVENT_PAUSE|ENABLE_VOLUME_EVENT_STOP)
#define ENABLE_VOLUME_FADE			(0x04)

namespace Graph2D
{
#if !defined(TARGET_WINDOWS)
	const int AudioPlayer::AUDIO_PLAYER_MAX_TRACK;
#endif
	AudioPlayer& AudioPlayer::getInstance()
	{
		static AudioPlayer instance;
		return instance;
	}

	AudioPlayer::AudioPlayer()
	{
		for(Environment* environment = &tracks[0]; environment < &tracks[AUDIO_PLAYER_MAX_TRACK]; environment++)
		{
			environment->player = NULL;
			environment->flag = 0;
		}
	}

	AudioPlayer::~AudioPlayer()
	{
		for(Environment* environment = &tracks[0]; environment < &tracks[AUDIO_PLAYER_MAX_TRACK]; environment++)
		{
			if(environment->player)
			{
				Implementation::AudioPlayer::release(environment->player);
			}
		}
	}

	AudioPlayer::Environment* AudioPlayer::find(const std::string filename)
	{
		for(Environment* environment = &tracks[0]; environment < &tracks[AUDIO_PLAYER_MAX_TRACK]; environment++)
		{
			if(environment->filename == filename)
				return environment;
		}
		return NULL;
	}

	int AudioPlayer::talk(const std::string& filename)
	{
		int index;
		for(index = 0; index < AUDIO_PLAYER_MAX_TRACK; index++)
		{
			if(!tracks[index].player)
				break;
		}
		if(index >= AUDIO_PLAYER_MAX_TRACK)
			return -1;

		tracks[index].player = Implementation::AudioPlayer::play(filename);
		tracks[index].filename = filename;
		tracks[index].flag = 0;

		return index;
	}

	int AudioPlayer::play(const std::string& filename, const float value, const float second)
	{
		if(find(filename))
			return -1;

		const int index = talk(filename);
		if(index >= 0)
		{
			Implementation::AudioPlayer::setLoopCount(tracks[index].player, -1);
			volume(index, 0.0f, 0.0f);
			volume(index, value, second);
		}

		return index;
	}

	void AudioPlayer::pause(const int track, const bool on, const float second)
	{
		if(track < 0 || track >= AUDIO_PLAYER_MAX_TRACK)
			return;

		if(!tracks[track].player)
			return;

		if(second <= 0.0f)
		{
			Implementation::AudioPlayer::pause(tracks[track].player, on);
		}
		else
		{
			if(on)
			{
				tracks[track].flag &= ENABLE_VOLUME_EVENT_MASK;
				tracks[track].flag |= ENABLE_VOLUME_EVENT_PAUSE;
				volume(track, 0.0f, second);
			}
			else
			{
				tracks[track].flag &= ENABLE_VOLUME_EVENT_MASK;
				volume(track, 1.0f, second);
			}
		}
	}

	void AudioPlayer::stop(const int track, const float second)
	{
		if(track < 0 || track >= AUDIO_PLAYER_MAX_TRACK)
			return;

		if(!tracks[track].player)
			return;

		if(!Implementation::AudioPlayer::playing(tracks[track].player))
			return;

		if(second <= 0.0f)
		{
			Implementation::AudioPlayer::stop(tracks[track].player);
		}
		else
		{
			tracks[track].flag &= ENABLE_VOLUME_EVENT_MASK;
			tracks[track].flag |= ENABLE_VOLUME_EVENT_STOP;
			volume(track, 0.0f, second);
		}
	}

	void AudioPlayer::volume(const int track, const float value, const float second)
	{
		if(track < 0 || track >= AUDIO_PLAYER_MAX_TRACK)
			return;

		if(!tracks[track].player)
			return;

		float vol = value;
		if(vol < 0.0f)
			vol = 0.0f;
		else if(vol > 1.0f)
			vol = 1.0f;

		if(second <= 0.0f)
		{
			Implementation::AudioPlayer::setVolume(tracks[track].player, vol);
		}
		else
		{
			tracks[track].deltaVolume = (vol - Implementation::AudioPlayer::getVolume(tracks[track].player)) * (1.0f / second);
			tracks[track].targetVolume = vol;
			tracks[track].timeVolume = second;
			tracks[track].flag |= ENABLE_VOLUME_FADE;
		}
	}

	const std::string& AudioPlayer::getFilename(const int track) const
	{
		return tracks[track].filename;
	}

	bool AudioPlayer::isPlaying(const int track) const
	{
		if(track >= 0 && track < AUDIO_PLAYER_MAX_TRACK)
		{
			return Implementation::AudioPlayer::playing(tracks[track].player);
		}
		else
		{
			return false;
		}
	}

	double AudioPlayer::getCurrentTime(const int track) const
	{
		return Implementation::AudioPlayer::getCurrentTime(tracks[track].player);
	}

	void AudioPlayer::setCurrentTime(const int track, const double second)
	{
		Implementation::AudioPlayer::setCurrentTime(tracks[track].player, second);
	}

	void AudioPlayer::onUpdate(const float deltaTime)
	{
		for(int i = 0; i < AUDIO_PLAYER_MAX_TRACK; i++)
		{
			Environment& environment = tracks[i];
			if(environment.player == NULL)
				continue;

			if(Implementation::AudioPlayer::playing(environment.player))
			{
				if(environment.flag & ENABLE_VOLUME_FADE)
				{
					Implementation::AudioPlayer::addVolume(environment.player, environment.deltaVolume * deltaTime);
					environment.timeVolume -= deltaTime;
					if(environment.timeVolume <= 0)
					{
						Implementation::AudioPlayer::setVolume(environment.player, environment.targetVolume);
						if(environment.flag & ENABLE_VOLUME_EVENT_PAUSE)
						{
							Implementation::AudioPlayer::pause(environment.player, true);
						}
						if(environment.flag & ENABLE_VOLUME_EVENT_STOP)
						{
							Implementation::AudioPlayer::stop(environment.player);
						}
						environment.flag &= ~ENABLE_VOLUME_FADE;
					}
				}
			}

			// 再生していないトラックを解放します
			if(!Implementation::AudioPlayer::playing(environment.player))
			{
				Implementation::AudioPlayer::release(environment.player);
				environment.filename.clear();
				environment.player = NULL;
			}
		}
	}
}
